//
//  FPluginCollectionViewProxy.m
//  Foundation
//
//  Created by 三井 on 2019/10/21.
//

#import "FPluginCollectionViewProxy.h"
#import "FPluginCollectionViewFake.h"
#import "UICollectionView+FPlugin.h"
#import "FPluginWrappedData.h"
#import <FFoundation/FMacroDefine.h>

@interface FPluginCollectionViewProxy () <UICollectionViewDelegateFlowLayout, UICollectionViewDataSource>

@property (nonatomic, strong) UICollectionView *collectionView;
@property (nonatomic, weak) id<UICollectionViewDelegate> sourceDelegate;
@property (nonatomic, weak) id<UICollectionViewDataSource> sourceDataSource;

@end

@implementation FPluginCollectionViewProxy

- (instancetype)initWithSource:(UICollectionView *)source {
    if (self = [super initWithSource:source]) {
        self.collectionView = source;
        
        self.sourceDelegate = source.delegate;
        self.sourceDataSource = source.dataSource;
        source.delegate = self;
        source.dataSource = self;
    }
    return self;
}

- (FPluginFake *)prepareArg:(FPluginArg *)arg forPlugin:(id<FPlugin>)plugin {
    FPluginFake *fake = [super prepareArg:arg forPlugin:plugin];
    arg.collectionView = (UICollectionView *)fake;
    return fake;
}

- (FPluginFake *)fakeForIdentifier:(NSString *)identifier {
    return [FPluginCollectionViewFake fakeFor:self.collectionView];
}

#pragma mark - Collection
#pragma mark - Scroll
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    for (FPluginCollectionViewFake *fake in self.pluginFakeMap.allValues) {
        F_macro_delegate(void, fake.delegate, _cmd, fake);
    }
    F_macro_delegate(void, self.sourceDelegate, _cmd, scrollView);
}

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
    for (FPluginCollectionViewFake *fake in self.pluginFakeMap.allValues) {
        F_macro_delegate(void, fake.delegate, _cmd, fake);
    }
    F_macro_delegate(void, self.sourceDelegate, _cmd, scrollView);
}

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
    for (FPluginCollectionViewFake *fake in self.pluginFakeMap.allValues) {
        if ([fake.delegate respondsToSelector:_cmd]) {
            [fake.delegate scrollViewDidEndDragging:(UIScrollView *)fake willDecelerate:decelerate];
        }
    }
    if ([self.sourceDelegate respondsToSelector:_cmd]) {
        [self.sourceDelegate scrollViewDidEndDragging:scrollView willDecelerate:decelerate];
    }
}

#pragma mark - Delegate
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
    FPluginWrappedData *data = [collectionView objectAtIndexPath:indexPath];
    FPluginCollectionViewFake *fake = (FPluginCollectionViewFake *)[self fakeForData:data];
    FPlugin_Proxy_Fake(void, fake.delegate, self.sourceDelegate, fake, collectionView, indexPath);
}

- (void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath {
    FPluginWrappedData *data = [collectionView objectAtIndexPath:indexPath];
    FPluginCollectionViewFake *fake = (FPluginCollectionViewFake *)[self fakeForData:data];
    FPlugin_Proxy_Fake(void, fake.delegate, self.sourceDelegate, fake, collectionView, cell, indexPath);
}

- (void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath {
    FPluginWrappedData *data = [collectionView objectAtIndexPath:indexPath];
    FPluginCollectionViewFake *fake = (FPluginCollectionViewFake *)[self fakeForData:data];
    FPlugin_Proxy_Fake(void, fake.delegate, self.sourceDelegate, fake, collectionView, cell, indexPath);
}

#pragma mark - DataSource
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
    __block NSUInteger num = 0;
    [self.pluginFakeMap enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, FPluginCollectionViewFake *  _Nonnull obj, BOOL * _Nonnull stop) {
        if ([obj.dataSource respondsToSelector:@selector(numberOfSectionsInCollectionView:)]) {
            num += [obj.dataSource numberOfSectionsInCollectionView:(UICollectionView *)obj];
        } else {
            num += 1;
        }
    }];
    num += [self.sourceDataSource numberOfSectionsInCollectionView:collectionView];
    
    if (num <= 1) {
        self.sectionType = FPluginArraySectionTypeSingle;
        num = 1;
    } else if (num <= collectionView.plg_datas.sectionNum) {
        // 比自然组少，比1大
        num = collectionView.plg_datas.sectionNum;
        self.sectionType = FPluginArraySectionTypeNatural;
    } else if (num <= collectionView.plg_datas.count) {
        // 比自然组大，比完全组少
        num = collectionView.plg_datas.count;
        self.sectionType = FPluginArraySectionTypeEntire;
    } else {
        // 比完全组还大
        num = collectionView.plg_datas.count;
        self.sectionType = FPluginArraySectionTypeEntire;
    }

    return num;
}

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
    return [collectionView.plg_datas numberOfItemsInSection:section withSectionType:self.sectionType];
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    FPluginWrappedData *data = [collectionView objectAtIndexPath:indexPath];
    FPluginCollectionViewFake *fake = (FPluginCollectionViewFake *)[self fakeForData:data];
    if ([fake.dataSource respondsToSelector:@selector(collectionView:cellForItemAtIndexPath:)]) {
        return [fake.dataSource collectionView:(UICollectionView *)fake cellForItemAtIndexPath:indexPath];
    }
    
    return [self.sourceDataSource collectionView:collectionView cellForItemAtIndexPath:indexPath];
}

- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {
    FPluginWrappedData *data = [collectionView objectAtIndexPath:indexPath];
    FPluginCollectionViewFake *fake = (FPluginCollectionViewFake *)[self fakeForData:data];
    if ([fake.dataSource respondsToSelector:@selector(collectionView:viewForSupplementaryElementOfKind:atIndexPath:)]) {
        return [fake.dataSource collectionView:(UICollectionView *)fake viewForSupplementaryElementOfKind:kind atIndexPath:indexPath];
    }
    
    return [self.sourceDataSource collectionView:collectionView viewForSupplementaryElementOfKind:kind atIndexPath:indexPath];
}

#pragma mark - Flow
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section {
    FPluginWrappedData *data = [collectionView objectAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:section]];
    FPluginCollectionViewFake *fake = (FPluginCollectionViewFake *)[self fakeForData:data];
    if ([fake.delegate respondsToSelector:@selector(collectionView:layout:referenceSizeForFooterInSection:)]) {
        return [((id<UICollectionViewDelegateFlowLayout>)fake.delegate) collectionView:(UICollectionView *)fake layout:collectionViewLayout referenceSizeForFooterInSection:section];
    }
    if ([self.sourceDelegate respondsToSelector:@selector(collectionView:layout:referenceSizeForFooterInSection:)]) {
        return [((id<UICollectionViewDelegateFlowLayout>)self.sourceDelegate) collectionView:collectionView layout:collectionViewLayout referenceSizeForFooterInSection:section];
    }
    if ([collectionViewLayout isKindOfClass:UICollectionViewFlowLayout.class]) {
        return [((UICollectionViewFlowLayout *)collectionViewLayout) footerReferenceSize];
    }
    return CGSizeZero;
}

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
    FPluginWrappedData *data = [collectionView objectAtIndexPath:indexPath];
    FPluginCollectionViewFake *fake = (FPluginCollectionViewFake *)[self fakeForData:data];
    if ([fake.delegate respondsToSelector:@selector(collectionView:layout:sizeForItemAtIndexPath:)]) {
        return [((id<UICollectionViewDelegateFlowLayout>)fake.delegate) collectionView:(UICollectionView *)fake layout:collectionViewLayout sizeForItemAtIndexPath:indexPath];
    }
    if ([self.sourceDelegate respondsToSelector:@selector(collectionView:layout:sizeForItemAtIndexPath:)]) {
        return [((id<UICollectionViewDelegateFlowLayout>)self.sourceDelegate) collectionView:collectionView layout:collectionViewLayout sizeForItemAtIndexPath:indexPath];
    }
    if ([collectionViewLayout isKindOfClass:UICollectionViewFlowLayout.class]) {
        return [((UICollectionViewFlowLayout *)collectionViewLayout) itemSize];
    }
    return CGSizeZero;
}

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
    FPluginWrappedData *data = [collectionView objectAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:section]];
    FPluginCollectionViewFake *fake = (FPluginCollectionViewFake *)[self fakeForData:data];
    if ([fake.delegate respondsToSelector:@selector(collectionView:layout:insetForSectionAtIndex:)]) {
        return [((id<UICollectionViewDelegateFlowLayout>)fake.delegate) collectionView:(UICollectionView *)fake layout:collectionViewLayout insetForSectionAtIndex:section];
    }
    if ([self.sourceDelegate respondsToSelector:@selector(collectionView:layout:insetForSectionAtIndex:)]) {
        return [((id<UICollectionViewDelegateFlowLayout>)self.sourceDelegate) collectionView:collectionView layout:collectionViewLayout insetForSectionAtIndex:section];
    }
    if ([collectionViewLayout isKindOfClass:UICollectionViewFlowLayout.class]) {
        return [((UICollectionViewFlowLayout *)collectionViewLayout) sectionInset];
    }
    return UIEdgeInsetsZero;
}

- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section {
    FPluginWrappedData *data = [collectionView objectAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:section]];
    FPluginCollectionViewFake *fake = (FPluginCollectionViewFake *)[self fakeForData:data];
    if ([fake.delegate respondsToSelector:@selector(collectionView:layout:minimumLineSpacingForSectionAtIndex:)]) {
        return [((id<UICollectionViewDelegateFlowLayout>)fake.delegate) collectionView:(UICollectionView *)fake layout:collectionViewLayout minimumLineSpacingForSectionAtIndex:section];
    }
    if ([self.sourceDelegate respondsToSelector:@selector(collectionView:layout:minimumLineSpacingForSectionAtIndex:)]) {
        return [((id<UICollectionViewDelegateFlowLayout>)self.sourceDelegate) collectionView:collectionView layout:collectionViewLayout minimumLineSpacingForSectionAtIndex:section];
    }
    if ([collectionViewLayout isKindOfClass:UICollectionViewFlowLayout.class]) {
        return [((UICollectionViewFlowLayout *)collectionViewLayout) minimumLineSpacing];
    }
    return 0.f;
}

- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section {
    FPluginWrappedData *data = [collectionView objectAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:section]];
    FPluginCollectionViewFake *fake = (FPluginCollectionViewFake *)[self fakeForData:data];
    if (fake && [fake.delegate respondsToSelector:@selector(collectionView:layout:minimumInteritemSpacingForSectionAtIndex:)]) {
        return [((id<UICollectionViewDelegateFlowLayout>)fake.delegate) collectionView:(UICollectionView *)fake layout:collectionViewLayout minimumInteritemSpacingForSectionAtIndex:section];
    }
    if ([self.sourceDelegate respondsToSelector:@selector(collectionView:layout:minimumInteritemSpacingForSectionAtIndex:)]) {
        return [((id<UICollectionViewDelegateFlowLayout>)self.sourceDelegate) collectionView:collectionView layout:collectionViewLayout minimumInteritemSpacingForSectionAtIndex:section];
    }
    if ([collectionViewLayout isKindOfClass:UICollectionViewFlowLayout.class]) {
        return [((UICollectionViewFlowLayout *)collectionViewLayout) minimumInteritemSpacing];
    }
    return 0.f;
}

@end
